/**
 *  Version:     @(#)aio_event.h    0.2.05 20/10/2006
 *
 *  Authors:     Hailong Xia <hlxxxx@gmail.com>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty
 *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *  the GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 *  Boston, MA 02111-1307  USA
 */

#ifndef __AIO_EVENT_H
#define __AIO_EVENT_H

/**
 * This file is a event templete file for AIO user. Default user needn't 
 * make any modification to use AIO event. But When user want to specify
 * a especial event driver instead of AIO event, the user must be manual
 * modify this file and re-complie it.
 */

#ifdef _AIO_CUSTOM_EVENT
# ifdef _AIO_LIBEVENT
#  include <event.h>   /* Libevent 1.3 or later version */
#  define AIO_EV_ERROR     0x00000000 
#  define AIO_EV_READ      EV_READ
#  define AIO_EV_WRITE     EV_WRITE
#  define AIO_EV_TIMEOUT   EV_TIMEOUT
#  define AIO_EV_RPERSIST  EV_PERSIST
#  define AIO_EV_WPERSIST  EV_PERSIST
#  define aio_evbase_create(size) event_init() 
#  define aio_evbase_destroy(eb) event_base_free(eb)
#  define aio_evbase_set(ev, eb) event_base_set(eb, ev) 
#  define aio_event_set(ev, fd, events, cb, arg) event_set(ev, fd, events, cb, arg)
#  define aio_event_add(ev, tv) event_add(ev, tv)
#  define aio_event_del(ev) event_del(ev)
#  define aio_event_shutdown(eb, tv)  event_base_loopexit(eb, tv)
#  define aio_event_dispatch(eb) event_base_dispatch(eb)
#  define AIO_EVENT struct event
#  define AIO_EVBASE struct event_base
# else
#  error "Please specify a event dirver for AIO"
# endif
#else /* Undefine _AIO_CUSTOM_EVENT */

/** 
 * This is a simple libevent implement. Here I used array instead of
 * queue to maintain a lot of file descriptors. It improves some 
 * performance when there are too many fds. But when there are few fds, 
 * it may waste a little memory.
 */

#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/time.h>
#endif

#include "aio_tree.h"

#ifdef __cplusplus
extern "C" {
#endif

#define AIO_EV_ERROR            0x00000001
#define AIO_EV_READ             0x00000010
#define AIO_EV_WRITE            0x00000100
#define AIO_EV_TIMEOUT          0x00001000
#define AIO_EV_RPERSIST         0x00000002
#define AIO_EV_WPERSIST         0x00100020

#define TIMEOUT_DEFAULT {5, 0}

typedef struct aio_event {
        int                 fd;
        int                 pfdi; /* location in p_fds array. */
        short               events;
        void                (*cb)(int, short, void *);
        void                *cbarg;
        struct timeval      timeout;
        struct aio_evbase   *eb;
        RB_ENTRY(aio_event) time_node;
} AIO_EVENT;

typedef struct aio_evbase {
        int                           size; 
        struct pollfd                 *p_fds;
        struct aio_event              **r_evs;
        struct aio_event              **w_evs;
        int                           maxpfdi; /* max valid location of p_fds array. */
        struct timeval                timeflag;
        RB_HEAD(time_tree, aio_event) timetree;
        struct aio_event              timer_event; /* dispatch timer */
        int                           exit; /* shutdown: -1, timeout: 1 */
} AIO_EVBASE;

/* success return valid pointer, fail return NULL */
struct aio_evbase* aio_evbase_create(int size);

/* must be not call this function in callback function of event */
void aio_evbase_destroy(struct aio_evbase *eb);

int aio_evbase_set(struct aio_event *ev, struct aio_evbase *eb);

/* success return 0, fail return -1 */
void aio_event_set(struct aio_event *ev, int fd,
        short events, void (*cb)(int, short, void *), void *arg);

/* Success return 0, fail return -1 */
int aio_event_add(struct aio_event *ev, struct timeval *tv);

int aio_event_del(struct aio_event *ev);

/** 
 * Call in the callback function of event to stop dispath
 * The second argument tv value is NULL indication permence. 
 */
int aio_event_shutdown(struct aio_evbase *eb, struct timeval *tv);

/* success return 0, fail return -1 */
int aio_event_dispatch(struct aio_evbase *eb);

#ifdef __cplusplus
}
#endif

#endif /* Undefine _AIO_CUSTOM_EVENT */

#define aio_evtimer_set(ev, cb, arg) \
        aio_event_set(ev, -1, AIO_EV_TIMEOUT, cb, arg)
#define aio_evtimer_add(ev, tv) aio_event_add(ev, tv)
#define aio_evtimer_del(ev) aio_event_del(ev)

#endif /* __AIO_EVENT_H */

